package com.tanjun.data.components;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.tanjun.data.service.DelayQueueHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;

@Component
@Slf4j
public class QueueApplicationListener implements ApplicationListener<ApplicationEvent> {

    @Autowired
    private RedisDelayQueueUtil redisDelayQueueUtil;
    @Autowired
    private Executor executor;

    @Autowired(required = false)
    private List<DelayQueueHandler> listHandler;

    /**
     * Handle an application event.
     *
     * @param event the event to respond to
     */
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            // 容器准备完毕，bean都已经创建完成，但是不保证应用程序已经完全启动
            // 如果要在这里做一些资源初始化的操作，需要注意可能会有并发问题

        } else if (event instanceof ContextClosedEvent) {
            // 容器关闭

        } else if (event instanceof ApplicationReadyEvent) {
            // 应用程序已经准备好接受请求
            registerDelayQueueRunner();
        }

    }



    public void registerDelayQueueRunner() {

        if (CollectionUtils.isEmpty(listHandler)) {
            log.info("不存在延迟消息队列");
            return;
        }
        Map<String, Class> queueNameMap = new HashMap<>();
        for (DelayQueueHandler handler : listHandler) {
            if (queueNameMap.containsKey(handler.getQueueName())) {
                throw new RuntimeException(StrUtil.format("延迟队列%s存在重复的处理方法,%s,%s"
                        , handler.getQueueName(), queueNameMap.get(handler.getQueueName()), handler.getClass()));
            }
            queueNameMap.put(handler.getQueueName(), handler.getClass());

            new Thread(() -> { //这里不采用线程池的原因是担心线程池的数量小于需要处理的队列数量，导致一些一直在等待中
                log.info("延迟队列:{},监听线程:{},处理类:{}", handler.getQueueName(),
                        Thread.currentThread().getName(), handler.getClass());
                while (true) {
                    Object d = redisDelayQueueUtil.getDelayQueue(handler.getQueueName());
                    executor.execute(() -> {
                        log.info("延迟队列:{},处理线程:{},msg:{}", handler.getQueueName(), Thread.currentThread().getName(), JSON.toJSONString(d));
                        handler.handle(d);
                    });
                }
            }).start();
        }
    }


}
